/**全局指令
 * vue2* 切换 ==> vue3* 属性参考
 * // 在【vue2】中
 * - bind：只调用一次，指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
 * - inserted：被绑定元素插入父节点时调用 (仅保证父节点存在，但不一定已被插入文档中)。
 * - update：所在组件的 VNode 更新时调用，但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变，也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新。
 * - componentUpdated：指令所在组件的 VNode 及其子 VNode 全部更新后调用。
 * - unbind：只调用一次，指令与元素解绑时调用。
 *
 * // 在【vue3】中
 * - created：在绑定元素的 attribute 或事件监听器被应用之前调用。在指令需要附加在普通的 v-on 事件监听器调用前的事件监听器中时，这很有用。
 * - beforeMount：当指令第一次绑定到元素并且在挂载父组件之前调用。
 * - mounted：在绑定元素的父组件被挂载前调用。
 * - beforeUpdate：在更新包含组件的 VNode 之前调用。
 * - updated：在包含组件的 VNode 及其子组件的 VNode 更新后调用。
 * - beforeUnmount：在卸载绑定元素的父组件之前调用。
 * - unmounted：当指令与元素解除绑定且父组件已卸载时，只调用一次。
 * */
import {debounce} from "@/utils";

// 自定义拖拽指令
export const drag = (el:any) => {
    const oDiv = el // 当前元素
    const minTop = oDiv.getAttribute('drag-min-top') || 0
    const minMargin = oDiv.getAttribute('drag-min') || 0
    const ifMoveSizeArea = oDiv.getAttribute('size-area') || 20
    // body初始宽高
    let target = oDiv
    // 获取target最近一级的absolute节点
    while (window.getComputedStyle(target).position !== 'absolute' && target !== document.body) {
        target = target.parentElement
    }
    let target_parent = target.parentElement;
    // 获取距离target第二近的absolute节点
    if (window.getComputedStyle(target.parentElement).position !== 'absolute' && target.parentElement !== document.body) {
        while (window.getComputedStyle(target_parent).position !== 'absolute' && target_parent !== document.body) {
            target_parent = target_parent.parentElement
        }
    }
    // target_parent 初始宽高
    let initParentWidth = target_parent.offsetWidth
    let initParentHeight = target_parent.offsetHeight

    oDiv.onmousedown = (e: any) => {
        document.onselectstart = () => {
            return false
        }
        if (!target.getAttribute('init_x')) {
            target.setAttribute('init_x', target.offsetLeft)
            target.setAttribute('init_y', target.offsetTop)
        }

        // 初始坐标
        const initX = parseInt(target.getAttribute('init_x'))
        const initY = parseInt(target.getAttribute('init_y'))

        window.onresize = (e) => {
            debounce(()=>{
                let r = target_parent.offsetWidth - target.offsetWidth - minMargin
                if (target.offsetLeft + target.offsetWidth > target_parent.offsetWidth){
                    target.style.left = r + 'px'
                }
                let b = target_parent.offsetHeight - target.offsetHeight - minMargin
                if (target.offsetTop + target.offsetHeight > target_parent.offsetHeight){
                    target.style.top = b + 'px'
                }
            },500)()

        }

        // 鼠标按下，计算当前元素距离可视区的距离
        const disX = e.clientX - target.offsetLeft
        const disY = e.clientY - target.offsetTop

        document.onmousemove = e => {
            // 通过事件委托，计算移动的距离
            // 因为浏览器里并不能直接取到并且使用clientX、clientY,所以使用事件委托在内部做完赋值
            const l = e.clientX - disX
            const t = e.clientY - disY
            // 计算移动当前元素的位置，并且给该元素样式中的left和top值赋值
            if (minTop) {
                target.style.left = l + 'px'
                target.style.top = (t < minTop ? minTop : t) + 'px'
            } else {
                //计算左边距
                let r = target_parent.offsetWidth - target.offsetWidth - minMargin
                if (l < minMargin) target.style.left = minMargin + 'px'
                else if (l >= minMargin && l < r) target.style.left = l + 'px'
                else target.style.left = r + 'px'
                //计算上边距
                let b = target_parent.offsetHeight - target.offsetHeight - minMargin
                if (t < minMargin) target.style.top = minMargin + 'px'
                else if (t >= minMargin && t < b) target.style.top = t + 'px'
                else target.style.top = b + 'px'
            }
            //视口拖动修改偏移量
            let offsetX = initX + target_parent.offsetWidth - initParentWidth
            let offsetY = initY + target_parent.offsetHeight  - initParentHeight
            if (Math.abs(l - offsetX) > ifMoveSizeArea || Math.abs(t - offsetY) > ifMoveSizeArea) {
                target.setAttribute('dragged', '')
            } else {
                target.removeAttribute('dragged')
            }
        }
        document.onmouseup = e => {
            document.onmousemove = null
            document.onmouseup = null
            document.onselectstart = null
        }
        // return false不加的话可能导致黏连，拖到一个地方时div粘在鼠标上不下来，相当于onmouseup失效
        return false
    }
}
